import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';

class CircleBallWidget extends StatefulWidget {
  
  
  @override
  _CircleHeadWidgetState createState() => _CircleHeadWidgetState();
}

class _CircleHeadWidgetState extends State<CircleBallWidget> with SingleTickerProviderStateMixin {

  double progress = 0;
  AnimationController _controller;
  Animation<double> _animation;
  double beingX = 0;
  double endX = 0;
  final _spring = const SpringDescription(
    mass: 30,
    stiffness: 1000,
    damping: 1,
  );

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 80000))
      ..addListener(() {
        if(_controller.isCompleted) {
          _beginAnimation();
        }
      });
    _beginAnimation();
  }

  void _updateProgress(double p) {
    setState(() {
      if(p < 0){
        if(progress >= 1) progress = 0; // 顺序不能乱
        progress += 0.01;
      } else {
        progress -= 0.01;
        if(progress <= 0) progress = 1;
      }
    });
  }

  double _normalizeVelocity(Offset velocity, Size size) {
    final normalizedVelocity = Offset(
      velocity.dx / size.width,
      velocity.dy / size.height,
    );
    return -normalizedVelocity.distance;
  }

  void _runAnimation(Offset velocity, Size size) {
    double temp = beingX - endX;
    double _currPro = temp / size.width;
    double begin = 0;
    double end = 0;
    if(beingX < endX) {
      begin = progress;
      end = _currPro + progress;
    } else {
      begin = -_currPro;
      end = (progress - _currPro).abs();
    }
    _animation = _controller.drive(
      Tween(
        begin: begin,
        end: end,
      ),
    );

    final simulation =
        SpringSimulation(_spring, 0, 1, _normalizeVelocity(velocity, size));

    _controller.animateWith(simulation);
  }

  void _beginAnimation() {
    double begin = progress;
    double end = 1 + progress;
    _animation = _controller.drive(
      Tween(
        begin: end,
        end: begin,
      ),
    );
    _animation.addListener(() { 
      setState(() {
          progress = _animation.value;
        });
    });
    _controller.repeat();
  }

  Widget _create(double angle, int index, double left, double width){
    final imgIndex = index + 1 > 32 ? 32 - index + 1 : index + 1;
    return _StackChild(
              beginAngle: angle,
              progress: progress,
              index: index,
              left: left,
              radiusA: width,
              child: Image.asset("assets/q$imgIndex.png", fit: BoxFit.scaleDown,),
            );
  }

  List<Widget> _createChildern(BuildContext context) {

    List<Widget> res = [];
    final Size size = MediaQuery.of(context).size;
    final raduiA = size.width * 0.37;
    final left = (size.width - raduiA * 2) / 2.0;
    for(var i = 0.0; i< 360; i+=15) {
      res.add(_create(i, i ~/ 15, left, raduiA));
    }
    return res;
  }

  @override
  Widget build(BuildContext context) {
    
    final size = MediaQuery.of(context).size;

    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onHorizontalDragStart: (details) {
        beingX = details.localPosition.dx;
        _controller?.stop(canceled: true);
      },
      onHorizontalDragUpdate: (details){
        if(details.delta.dx == 0) return;
        endX = details.localPosition.dx;
        _updateProgress(details.delta.dx);
      },
      onHorizontalDragEnd: (details){
        if((beingX - endX).abs() < 10) {
          _beginAnimation();
          return;
        }
        _runAnimation(details.velocity.pixelsPerSecond, size);
      },
      child: Container(
        child: Stack(
          children: [
            Center(
              child: Transform.rotate(
                angle: -0.3,
                child: SizedBox(
                  height: 300,
                  child: Stack(
                    overflow: Overflow.visible,
                    children: _createChildern(context),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _StackChild extends StatelessWidget {
  
  final double progress; // 角度 0 ~ 1
  final double top; // 上边距
  final double left; // 左边距
  final double beginAngle; // 开始角度
  final int index;
  final double radiusA; // 椭圆长半轴
  final Widget child;
  _StackChild({
    Key key, 
    this.child,
    this.progress = 0, 
    this.top = 0,
    this.left = 0,
    this.radiusA,
    this.beginAngle = 0,
    this.index,
  }) : super(key: key);

  /// 椭圆
  Offset _ovalComputeOffset(double angle, Offset center, double radius) {
    final double radian = pi / 180.0 * (angle + beginAngle);
    
    final ovalA = radius; // 长半径
    final ovalB = 30;   // 短半径

    Offset res;
    double x = ovalA * cos(radian);
    double y = ovalB * sin(radian);
    res = Offset(x, y);
    return Offset(res.dx + center.dx, res.dy + center.dy);
  }

  /// 斜椭圆
  Offset _ovalTitlComputeOffset(double angle, Offset center, double radius) {
    final double radian = pi / 180.0 * (angle + beginAngle);
    
    final ovalA = radius; // 长半径
    final ovalB = 30.0;   // 短半径
    final titlAngle = -0.16; // 倾斜角度

    Offset res;
    double x = ovalA * cos(radian) * cos(titlAngle) - ovalB * sin(radian) * sin(titlAngle);
    double y = ovalA * cos(radian) * sin(titlAngle) - ovalB * sin(radian) * cos(titlAngle);
    res = Offset(x, y);
    return Offset(res.dx + center.dx, res.dy + center.dy);
  }

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    Offset center = Offset((size.width - radiusA) / 2, 100); // 圆中心点
    Offset ofset = _ovalComputeOffset(progress * 360, center, radiusA);
    double imageH = ofset.dy - 50;
    return Positioned(
      top: ofset.dy + top,
      left: ofset.dx + left,
      child: Offstage(
        offstage: ofset.dy + top < 85,
        child: Container(
          height: imageH,
          width: imageH,
          child: child,
        )
      ),
    );
  }
}